#include "meta.h"

#include "raft/raft.h"
#include "slash/coding.h"

static const std::string kCurrentTerm = "CURRENTTERM";
static const std::string kVoteForIp = "VOTEFORIP";
static const std::string kVoteForPort = "VOTEFORPORT";
static const std::string kCommitIndex = "COMMITINDEX";
static const std::string kLastApplied = "APPLYINDEX";
static const std::string kFencingToken = "FENCINGTOKEN";

namespace libraft {
Meta::Meta(const std::shared_ptr<rocksdb::DB>& meta)
    : meta_(meta) {}

Meta::~Meta() {}

void Meta::Open() {
  if (GetCurrentTerm() == 0) {
    SetCurrentTerm(0);
  }

  if (GetVotedForIp() == "") {
    SetVotedForIp("");
  }

  if (GetVotedForPort() == 0) {
    SetVotedForPort(0);
  }

  if (GetCommitIndex() == 0) {
    SetCommitIndex(0);
  }

  if (GetLastApplied() == 0) {
    SetLastApplied(0);
  }
}

uint64_t Meta::GetCurrentTerm() {
  std::string buf;
  uint64_t term = 0;
  rocksdb::Status status =
      meta_->Get(rocksdb::ReadOptions(), kCurrentTerm, &buf);
  if (status.IsNotFound()) {
    return 0;
  }

  term = slash::DecodeFixed64(buf.c_str());
  return term;
}

void Meta::SetCurrentTerm(const uint64_t current_term) {
  std::string term;
  slash::PutFixed64(&term, current_term);
  meta_->Put(rocksdb::WriteOptions(), kCurrentTerm, term);
}

std::string Meta::GetVotedForIp() {
  std::string buf;
  rocksdb::Status status =
      meta_->Get(rocksdb::ReadOptions(), kVoteForIp, &buf);
  if (status.IsNotFound()) {
    return std::string("");
  }
  return buf;
}

int Meta::GetVotedForPort() {
  std::string buf;
  int port = 0;
  rocksdb::Status status =
      meta_->Get(rocksdb::ReadOptions(), kVoteForPort, &buf);
  if (status.IsNotFound()) {
    return 0;
  }

  port = slash::DecodeFixed64(buf.c_str());
  return port;
}

void Meta::SetVotedForIp(const std::string& ip) {
  std::string buf;
  meta_->Put(rocksdb::WriteOptions(), kVoteForIp, ip);
}

void Meta::SetVotedForPort(const int port) {
  std::string buf;
  slash::PutFixed64(&buf, port);
  meta_->Put(rocksdb::WriteOptions(), kVoteForPort, buf);
}

uint64_t Meta::GetCommitIndex() {
  std::string buf;
  uint64_t commit_index;
  rocksdb::Status status =
      meta_->Get(rocksdb::ReadOptions(), kCommitIndex, &buf);
  if (status.IsNotFound()) {
    return 0;
  }

  commit_index = slash::DecodeFixed64(buf.c_str());
  return commit_index;
}

void Meta::SetCommitIndex(const uint64_t commit_index) {
  std::string buf;
  slash::PutFixed64(&buf, commit_index);
  meta_->Put(rocksdb::WriteOptions(), kCommitIndex, buf);
}

uint64_t Meta::GetLastApplied() {
  std::string buf;
  uint64_t last_applied = 0;
  rocksdb::Status status =
      meta_->Get(rocksdb::ReadOptions(), kLastApplied, &buf);
  if (status.IsNotFound()) {
    return 0;
  }

  last_applied = slash::DecodeFixed64(buf.c_str());
  return last_applied;
}

void Meta::SetLastApplied(uint64_t last_applied) {
  std::string buf;
  slash::PutFixed64(&buf, last_applied);
  meta_->Put(rocksdb::WriteOptions(), kLastApplied, buf);
}

}  // namespace libraft